<template>
  <view class="mxp-notice" @click="clickHandler">
    <slot name="icon">
      <view v-if="showIcon" class="left-icon">
        <mxp-icon name="tongzhi" :color="color" size="18px"></mxp-icon>
      </view>
    </slot>
    <view :id="noticeContentViewId" class="content-view">
      <view :id="noticeContentTextViewId" ref="textViewRef" class="text-no-nvuw-view text-view" :style="[animationStyle]">
        <text v-for="(item, index) in innerText" :key="index" :style="[textStyle]">{{ item }}</text>
      </view>
    </view>
    <view v-if="['arrows', 'close'].includes(iconType)" class="right-icon">
      <mxp-icon v-if="iconType === 'arrows'" name="youjiantou" size="14px" :color="color"></mxp-icon>
      <mxp-icon v-if="iconType === 'close'" key="mxp-icon-2" name="guanbi" size="14px" :color="color" @click="close"></mxp-icon>
    </view>
  </view>
</template>

<script lang="ts" setup>
  import { type CSSProperties, type PropType, computed, getCurrentInstance, onMounted, onUnmounted, ref, shallowReactive, watch } from 'vue';
  import { publicStyeProps } from '../../mxp-tool/utils/public-props';
  import type { $AllColorStr, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import MxpIcon from '../../mxp-icon/mxp-icon.vue';
  import { getDomSize } from '../../mxp-tool/utils/dom';
  import { getOnlyID } from '../../mxp-tool/utils/common';
  import type { ViewInstance } from 'mxp-uni-types';

  defineOptions({
    name: 'mxp-notice-row',
  });

  const props = defineProps({
    /** 显示的内容，数组 */
    text: { type: [Array, String] as PropType<string[] | string>, default: '' },
    /** 是否显示左侧的音量图标 */
    showIcon: { type: Boolean, default: true },
    /** 右侧图标  arrows-显示右箭头，close-显示关闭图标，none-不显示图标 */
    iconType: { type: String as PropType<'arrows' | 'close' | 'none'>, default: 'close' },
    /** 文字颜色，各图标也会使用文字颜色 */
    color: { type: String as PropType<$AllColorStr>, default: '#E6A23C' },
    /** 水平滚动时的滚动速度，即每秒滚动多少px(px)，这有利于控制文字无论多少时，都能有一个恒定的速度 */
    speed: { type: Number, default: 80 },
    /** 字体大小 */
    fontSize: { type: String as PropType<$SizeUnitStr>, default: '14px' },
    ...publicStyeProps,
  });
  defineSlots<{
    /** 自定义图标 */
    icon: () => void;
  }>();
  const emits = defineEmits<{
    (e: 'click', index: number): void;
    (e: 'close'): void;
  }>();
  // #ifdef APP-NVUE
  const animation = uni.requireNativePlugin('animation');
  const textViewRef = ref<ViewInstance | null>(null);
  // #endif

  const instance = getCurrentInstance();

  const data = shallowReactive({
    stopAnimation: false,
    webviewHide: false,
    animationDuration: '0', // 动画执行时间
    animationPlayState: 'paused', // 动画的开始和结束执行
    nvueInit: true, // nvue下，内容发生变化，导致滚动宽度也变化，需要标志为是否需要重新计算宽度 不能在内容变化时直接重新计算，因为nvue的animation模块上一次的滚动不是刚好结束，会有影响
    show: true,
  });

  const noticeContentViewId = getOnlyID('mxp-notice-content-view');
  const noticeContentTextViewId = getOnlyID('mxp-notice-content-text-view');

  const textStyle = computed<CSSProperties>(() => {
    return { color: props.color, fontSize: props.fontSize };
  });

  const animationStyle = computed<CSSProperties>(() => {
    return { animationDuration: data.animationDuration, animationPlayState: data.animationPlayState };
  });
  // 内部对用户传入的数据进一步分割，放到多个text标签循环，否则如果用户传入的字符串很长(100个字符以上)
  // 放在一个text标签中进行滚动，在低端安卓机上，动画可能会出现抖动现象，需要分割到多个text中可解决此问题
  const innerText = computed(() => {
    const result = [];
    // 每组text标签的字符长度
    const len = 30;
    const text = String(Array.isArray(props.text) ? props.text[0] || '' : props.text);
    const textArr = text.split('');
    for (let i = 0; i < textArr.length; i += len) {
      // 对拆分的后的text进行slice分割，得到的为数组再进行join拼接为字符串
      result.push(textArr.slice(i, i + len).join(''));
    }
    return result;
  });
  watch(
    () => [props.text, props.fontSize, props.speed],
    () => {
      // #ifdef APP-NVUE
      data.nvueInit = true;
      // #endif
      // #ifndef APP-NVUE
      vueAnimation();
      // #endif
    }
  );

  onMounted(() => {
    // #ifdef APP-PLUS
    // 在APP上(含nvue)，监听当前webview是否处于隐藏状态(进入下一页时即为hide状态)  如果webivew隐藏了，为了节省性能的损耗，应停止动画的执行，同时也是为了保持进入下一页返回后，滚动位置保持不变
    const pages = getCurrentPages();
    const page = pages[pages.length - 1];
    const currentWebview = page?.$getAppWebview?.();
    if (currentWebview) {
      currentWebview.addEventListener('hide', () => {
        data.webviewHide = true;
      });
      currentWebview.addEventListener('show', () => {
        data.webviewHide = false;
      });
    }
    // #endif

    init();
  });

  onUnmounted(() => {
    // #ifdef APP-NVUE
    data.stopAnimation = true;
    // #endif
  });

  /** 初始化 */
  function init() {
    // #ifdef APP-NVUE
    nvueAnimation();
    // #endif

    // #ifndef APP-NVUE
    vueAnimation();
    // #endif
  }
  // #ifndef APP-NVUE
  /** vue动画 */
  function vueAnimation() {
    let textWidth = 0;
    setTimeout(async () => {
      // 查询盒子和文字的宽度
      textWidth = (await getDomSize(`#${noticeContentTextViewId}`, instance)).width!;
      // 根据t=s/v(时间=路程/速度)，这里为何不需要加上#notice-box的宽度，因为中设置了.notice-content样式中设置了padding-left: 100%
      // 恰巧计算出来的结果中已经包含了#notice-box的宽度
      data.animationDuration = `${textWidth / props.speed}s`;
      // 这里必须这样开始动画，否则在APP上动画速度不会改变
      data.animationPlayState = 'paused';
      setTimeout(() => {
        data.animationPlayState = 'running';
      }, 10);
    }, 10);
  }
  // #endif

  // #ifdef APP-NVUE
  /** nvue 动画 */
  function nvueAnimation() {
    data.nvueInit = false;
    let boxWidth = 0;
    let textWidth = 0;
    setTimeout(async () => {
      // 查询盒子和文字的宽度
      textWidth = (await getDomSize(`#${noticeContentTextViewId}`, instance))!.width!;
      boxWidth = (await getDomSize(`#${noticeContentViewId}`, instance)).width!;
      animation.transition(textViewRef.value, { styles: { transform: `translateX(${boxWidth}px)` } }, () => {
        // 如果非禁止动画，则开始滚动
        !data.stopAnimation && loopAnimation(textWidth, boxWidth);
      });
    }, 10);
  }
  // #endif
  // #ifdef APP-NVUE
  /** 循环东湖 */
  function loopAnimation(textWidth: number, boxWidth: number) {
    animation.transition(
      textViewRef.value,
      {
        // 目标移动终点为-textWidth，也即当文字的最右边贴到盒子的左边框的位置
        styles: { transform: `translateX(-${textWidth}px)` },
        // 滚动时间的计算为，时间 = 路程(boxWidth + textWidth) / 速度，最后转为毫秒
        duration: ((boxWidth + textWidth) / props.speed) * 1000,
        delay: 10,
      },
      () => {
        animation.transition(
          textViewRef.value,
          {
            styles: {
              // 重新将文字移动到盒子的右边沿
              transform: `translateX(${data.stopAnimation ? 0 : boxWidth}px)`,
            },
          },
          () => {
            // 如果非禁止动画，则继续下一轮滚动
            if (!data.stopAnimation) {
              // 判断是否需要初始化计算尺寸
              if (data.nvueInit) {
                nvueAnimation();
              } else {
                loopAnimation(textWidth, boxWidth);
              }
            }
          }
        );
      }
    );
  }
  // #endif

  /** 点击通告栏 */
  function clickHandler() {
    emits('click', 0);
  }

  /** 点击右侧按钮，需要判断点击的是关闭图标还是箭头图标 */
  function close() {
    emits('close');
  }
</script>

<style lang="scss" scoped>
  /* #ifndef APP-NVUE */
  @keyframes loop-animation {
    0% {
      transform: translate3d(0, 0, 0);
    }

    100% {
      transform: translate3d(-100%, 0, 0);
    }
  }
  /* #endif */

  .mxp-notice {
    display: flex;
    flex-flow: row nowrap;
    align-items: center;
    justify-content: space-between;

    .left-icon {
      align-items: center;
      margin-right: 5px;
    }

    .right-icon {
      align-items: center;
      margin-left: 10px;
    }

    .content-view {
      display: flex;
      flex: 1;
      flex-flow: row nowrap;
      overflow: hidden;
      text-align: right;

      .text-view {
        display: flex;
        flex-flow: row nowrap;
        font-size: 14px;
      }

      .text-no-nvuw-view {
        // #ifndef APP-NVUE
        padding-left: 100%;
        word-break: keep-all;
        white-space: nowrap;
        animation: loop-animation 10s linear infinite both;
        // #endif
      }
    }
  }
</style>
